-- 分支切换 cleanup

-- target -> {key} -> {effect}
local bucket = {};


-- 作为内部存储数据的
local symbol = {}
-- 存储当前副作用
local activeEffect
function track(target, key)
    -- bucket -> targetTable(depsMap)
    local depsMap = bucket[target]
    if type(depsMap) ~= 'table' then
        depsMap = {};
        bucket[target] = depsMap
    end

    -- depsMap -> keyTable(deps)
    local deps = depsMap[key]
    if type(deps) ~= "table" then
        deps = {}
        depsMap[key] = deps
    end
    -- deps -> effect
    table.insert(deps, activeEffect.cb)
    table.insert(activeEffect.deps, deps)
end

function trigger(target, key)
    -- 读取depsMap
    local depsMap = bucket[target]
    if (type(depsMap) ~= "table") then
        return
    end
    local deps = depsMap[key]
    if (type(deps) ~= 'table') then
        return
    end
    -- deps遍历
    for i = 1, #deps, 1 do
        local fn = deps[i]
        print("trigger->fn", fn)
        if (type(fn) == "function") then
            fn();
        end
    end
end

local metatable = {
    __index = function(target, key)
        print("track", target, key, activeEffect)
        if (type(activeEffect.cb) == "function") then
            track(target, key)
        end
        return target[symbol][key]
    end,
    __newindex = function(target, key, value)
        print("trigger", target, key)
        local oldValue = target[symbol][key]
        target[symbol][key] = value

        if (oldValue ~= value) then
            trigger(target, key)
        end
    end
}

-- 代理数据
local function reactive(table)
    local proxy = {}
    proxy[symbol] = table
    setmetatable(proxy, metatable)
    return proxy
end

-- 转换为代理数据
local data = reactive({ text = "hello", other = '321', ok = true })

function cleanup(effectFn)
    for i = 1, #effectFn.deps, 1 do
        local deps = effectFn.deps[i]
        for j = 1, #deps, 1 do
            if (deps[j] == effectFn.cb) then
                table.remove(deps, j)
            end
        end
    end
end

function effect(fn)
    if (type(fn) == "function") then
        -- 保存的相关
        local effectFn;
        effectFn = {
            cb = function()
                cleanup(effectFn)
                activeEffect = effectFn
                -- get track
                fn()
            end,
            deps = {}
        }
        -- track
        effectFn.cb()
    end
    activeEffect = nil
end

effect(function()
    print("effect run")
    local i;
    if data.ok then
        i = data.text
    else
        i = "not"
    end
    print("i", i);
end);


data.ok = false
data.text = "fix value"

-- effect run
-- track   table: 00BFBE00 ok      table: 00BFC0A0
-- track   table: 00BFBE00 text    table: 00BFC0A0
-- i       hello
-- trigger table: 00BFBE00 ok
-- trigger->fn     function: 00BFC9D8
-- effect run
-- track   table: 00BFBE00 ok      table: 00BFC0A0
-- i       not
-- trigger table: 00BFBE00 text
-- trigger->fn     function: 00BFC9D8
-- effect run
-- track   table: 00BFBE00 ok      table: 00BFC0A0
-- i       not


-- effect run
-- track   table: 0090BD28 ok      table: 0090BC48
-- track   table: 0090BD28 text    table: 0090BC48
-- i       hello
-- trigger table: 0090BD28 ok
-- trigger->fn     function: 0090C1C0
-- effect run
-- track   table: 0090BD28 ok      table: 0090BC48
-- i       not
-- trigger table: 0090BD28 text